package cn.bellychang.ood.litejunit.v3.framework.runner;

import cn.bellychang.ood.litejunit.v3.framework.notification.RunListener;
import cn.bellychang.ood.litejunit.v3.framework.notification.RunNotifier;
import cn.bellychang.ood.litejunit.v3.framework.runners.TextListener;
import cn.bellychang.ood.litejunit.v3.framework.request.Request;
import cn.bellychang.ood.litejunit.v3.framework.runners.InitializationError;
import cn.bellychang.ood.litejunit.v3.framework.runners.TestClassRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ChangLiang
 * @date 2020/5/27
 */
public class JUnitCore {

    private RunNotifier notifier;

    /**
     * Create a new <code>JUnitCore</code> to run tests.
     */
    public JUnitCore() {
        notifier = new RunNotifier();
    }

    public static void runClass(Class<?> clz) {
        try {
            TestClassRunner runner = new TestClassRunner(clz);
            JUnitCore core = new JUnitCore();
            core.addListener(new TextListener());
            Result result = core.run(runner);
        } catch (InitializationError initializationError) {
            initializationError.printStackTrace();
        }
    }

    public static void main(String... args) {
        Result result = new JUnitCore().runMain(args);
        killAllThreads(result);
    }

    /**
     * Do not use. Testing purposes only.
     */
    private Result runMain(String... args) {
        System.out.println("JUnit version " + "4.0");
        List<Class> classes = new ArrayList<Class>();
        for (String each : args) {
            try {
                classes.add(Class.forName(each));
            } catch (ClassNotFoundException e) {
                System.out.println("Could not find class: " + each);
            }
        }
        RunListener listener = new TextListener();
        addListener(listener);
        return run(classes.toArray(new Class[0]));
    }

    private static void killAllThreads(Result result) {
        System.exit(result.wasSuccessful() ? 0 : 1);
    }



    public static Result runClasses(Class... classes) {
        return new JUnitCore().run(classes);
    }

    private Result run(Class... classes) {
        return run(Request.classes("All", classes));
    }

    private Result run(Request request) {
        return run(request.getRunner());
    }

    private Result run(Runner runner) {
        Result result = new Result();
        RunListener listener = result.createListener();
        addListener(listener);

        try {
            notifier.fireTestRunStarted(runner.getDescription());
            runner.run(notifier);
            notifier.fireTestRunFinished(result);
        } finally {
            removeListener(listener);
        }
        return result;
    }

    /**
     * Add a listener to be notified as the tests run.
     * @param listener the listener
     * @see RunListener
     */
    public void addListener(RunListener listener) {
        notifier.addListener(listener);
    }

    /**
     * Remove a listener.
     * @param listener the listener to remove
     */
    public void removeListener(RunListener listener) {
        notifier.removeListener(listener);
    }
}
